﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Takkou.Language
{
    // generic number
    public interface Number
    {
        double get();
    }

    // fixed valued number
    public class ValNumber : Number
    {
        private double value;

        public ValNumber(double v)
        {
            value = v;
        }

        public double get()
        {
            return value;
        }
    }

    // number got from a property of an object (ex: pos X of robot)
    public class RefNumber : Number
    {
        private Func<double> property;

        public RefNumber(Func<double> prop)
        {
            property = prop;
        }

        public double get()
        {
            return property();
        }
    }

    // number as a result of a binary expression or operation
    public class BinaryExpNumber : Number
    {
        public enum ExpType
        {
            ADD,   // +
            SUB,   // -
            MUL,   // *
            DIV,   // /
            POW,   // x^y
        }

        public Number Num1 { get; private set; }
        public Number Num2 { get; private set; }
        public ExpType Type { get; private set; }

        public BinaryExpNumber(ExpType type, Number n1, Number n2)
        {
            Num1 = n1;
            Num2 = n2;
            Type = type;
        }

        public double get()
        {
            switch (Type)
            {
                case ExpType.ADD:
                    return Num1.get() + Num2.get();
                case ExpType.SUB:
                    return Num1.get() - Num2.get();
                case ExpType.MUL:
                    return Num1.get() * Num2.get();
                case ExpType.DIV:
                    // TODO test if num2 == 0
                    return Num1.get() / Num2.get();
                case ExpType.POW:
                    return Math.Pow(Num1.get(), Num2.get());
            }
            // TODO throw an exception
            return 0;
        }
    }

    // number as a result of a unary expression or operation
    public class UnaryExpNumber : Number
    {
        public enum ExpType
        {
            SQRT,   // square root
            // TODO introduce others
        }

        public Number Num { get; private set; }
        public ExpType Type { get; private set; }

        public UnaryExpNumber(ExpType type, Number n)
        {
            Num = n;
            Type = type;
        }

        public double get()
        {
            switch (Type)
            {
                case ExpType.SQRT:
                    return Math.Sqrt(Num.get());
            }
            // TODO throw an exception
            return 0;
        }
    }
}
